package com.zeyu.framework.monitors.redis;

import com.zeyu.framework.monitors.Collector;
import com.zeyu.framework.monitors.redis.entity.RedisStatus;
import com.zeyu.framework.monitors.redis.service.RedisService;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.EnvironmentAware;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.RedisConnection;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.stereotype.Component;

import java.util.Date;
import java.util.Properties;

/**
 * 执行Mysql的采集任务，将来可能会被任务调度使用，都是独立的方法
 * Created by zeyuphoenix on 16/8/26.
 */
@Component
public class RedisCollector implements Collector, EnvironmentAware {

    // ================================================================
    // Constants
    // ================================================================

    /**
     * logger
     */
    private static final Logger logger = LoggerFactory.getLogger(RedisCollector.class);


    // ================================================================
    // Fields
    // ================================================================

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Autowired
    private RedisService redisService;

    // 最后一次采集的redis状态
    private RedisStatus redisStatus;

    // host
    private String host;

    // ================================================================
    // Constructors
    // ================================================================

    // ================================================================
    // Methods from/for super Interfaces or SuperClass
    // ================================================================

    @Override
    public void setEnvironment(Environment environment) {
        this.host = environment.getProperty("spring.redis.host", "127.0.0.1");
    }

    @Override
    public void collect() {
        logger.info("Redis收集任务启动...");

        if (redisConnectionFactory == null) {
            logger.info("Redis 连接池为空,未进行数据采集,请检查是否是分布式环境或Redis配置");
            return;
        }

        // 获取当前的状态
        redisStatus = getCurrentRedisServerStatus();

        redisStatus.setTime(new Date());

        // 保存信息到数据库
        redisService.save(this.redisStatus);
    }

    // ================================================================
    // Public or Protected Methods
    // ================================================================

    /**
     * 获取最后一次采集的mysql状态
     */
    public RedisStatus getRedisStatus() {
        return this.redisStatus;
    }

    /**
     * 获取当前Redis的状态
     */
    public RedisStatus getCurrentRedisServerStatus() {
        logger.debug("获取当前Redis的状态开始..");
        RedisStatus redisStatus = new RedisStatus();
        redisStatus.setStatus(false);
        RedisConnection redisConnection = null;
        try {
            redisConnection = redisConnectionFactory.getConnection();
            if (redisConnection != null) {
                Properties properties = redisConnection.info();

                // 基本信息,不变

                // Redis 服务器版本
                redisStatus.setVersion(getStringValue(properties.get("redis_version")));
                // redis地址
                redisStatus.setHost(this.host);
                // Redis 服务器的宿主操作系统
                redisStatus.setOs(getStringValue(properties.get("os")));
                // 架构（32 或 64 位）
                redisStatus.setArch(getStringValue(properties.get("arch_bits")));
                // Redis 所使用的事件处理机制
                redisStatus.setMultiplexingApi(getStringValue(properties.get("multiplexing_api")));
                // 服务器进程的 PID
                redisStatus.setProcess(getStringValue(properties.get("process_id")));
                // TCP/IP 监听端口
                redisStatus.setPort(getIntValue(properties.get("tcp_port")));
                // 自 Redis 服务器启动以来，经过的秒数
                redisStatus.setUptime(getLongValue(properties.get("uptime_in_seconds")));
                //配置文件的保存路径
                redisStatus.setConfigFile(getStringValue(properties.get("config_file")));

                // 一个标志值，记录集群功能是否已经开启
                redisStatus.setClusterEnabled(getIntValue(properties.get("cluster_enabled")) != 0);
                // 在编译时指定的， Redis 所使用的内存分配器。可以是 libc 、 jemalloc 或者 tcmalloc
                redisStatus.setMemAllocator(getStringValue(properties.get("mem_allocator")));


                // 递增信息-连接、key等

                // 这些信息属于持续增长项目,不可作图,每次获取后展示即可,也暂不保存数据库
                // 服务器已接受的连接请求数量
                redisStatus.setTotalConnectionsReceived(getLongValue(properties.get("total_connections_received")));
                // 服务器已执行的命令数量
                redisStatus.setTotalCommandsProcessed(getLongValue(properties.get("total_commands_processed")));
                // 因为过期而被自动删除的数据库键数量
                redisStatus.setExpiredKeys(getLongValue(properties.get("expired_keys")));
                // 因为最大客户端数量限制而被拒绝的连接请求数量
                redisStatus.setRejectedConnections(getLongValue(properties.get("rejected_connections")));
                // 查找数据库键成功的次数。
                redisStatus.setKeyspaceHits(getLongValue(properties.get("keyspace_hits")));
                // 因为最大内存容量限制而被驱逐（evict）的键数量
                redisStatus.setEvictedkeys(getLongValue(properties.get("evicted_keys")));
                // 查找数据库键失败的次数
                redisStatus.setKeyspacemisses(getLongValue(properties.get("keyspace_misses")));
                // 总输出字节数
                redisStatus.setTotalNetOutputBytes(getLongValue(properties.get("total_net_output_bytes")));
                // 总输入字节数
                redisStatus.setTotalNetInputBytes(getLongValue(properties.get("total_net_input_bytes")));


                // cpu信息
                // Redis服务器耗费的系统 CPU 。
                redisStatus.setUsedCpuSys(getFloatValue(properties.get("used_cpu_sys_children")));
                // Redis服务器耗费的用户 CPU 。
                redisStatus.setUsedCpuUser(getFloatValue(properties.get("used_cpu_user_children")));

                // 内存信息
                //由 Redis 分配器分配的内存总量，以字节（byte）为单位
                redisStatus.setUsedMemory(getFloatValue(properties.get("used_memory")));
                // 从操作系统的角度，返回 Redis 已分配的内存总量（俗称常驻集大小）。这个值和 top 、 ps等命令的输出一致。
                redisStatus.setUsedMemoryRss(getFloatValue(properties.get("used_memory_rss")));
                // Redis 的内存消耗峰值（以字节为单位）
                redisStatus.setUsedMemorypeak(getFloatValue(properties.get("used_memory_peak")));
                //used_memory_rss 和 used_memory 之间的比率
                redisStatus.setMemFragmentationRatio(getFloatValue(properties.get("mem_fragmentation_ratio")));

                // 其它
                // 服务器每秒钟执行的命令数量。
                redisStatus.setInstantaneousOpsPerSec(getIntValue(properties.get("instantaneous_ops_per_sec")));

                redisStatus.setStatus(true);
                redisStatus.setTime(new Date());
            }
        } catch (Exception e) {
            redisStatus.setStatus(false);
            logger.error("获取redis信息失败: ", e);
        } finally {
            try {
                if (redisConnection != null)
                    redisConnection.close();
            } catch (Exception ignored) {
            }
        }

        logger.debug("收集Redis信息完成");
        return redisStatus;
    }

    // ================================================================
    // Getter & Setter
    // ================================================================

    // ================================================================
    // Private Methods
    // ================================================================

    /*
  * 转换格式
  */
    private long getLongValue(Object oldValue) {
        if (oldValue != null && StringUtils.isNotEmpty(oldValue.toString())) {
            return Long.valueOf(oldValue.toString().trim());
        }
        return 0L;
    }

    /*
     * 转换格式
     */
    private int getIntValue(Object oldValue) {
        if (oldValue != null && StringUtils.isNotEmpty(oldValue.toString())) {
            return Integer.valueOf(oldValue.toString().trim());
        }
        return 0;
    }

    /*
    * 转换格式
    */
    private String getStringValue(Object oldValue) {
        if (oldValue != null) {
            return oldValue.toString().trim();
        }
        return "";
    }

    /*
    * 转换格式
    */
    private float getFloatValue(Object oldValue) {
        if (oldValue != null && StringUtils.isNotEmpty(oldValue.toString())) {
            return Float.valueOf(oldValue.toString().trim());
        }
        return 0f;
    }

    // ================================================================
    // Inner or Anonymous Class
    // ================================================================

    // ================================================================
    // Test Methods
    // ================================================================

}
